﻿/* ***************************************************************************************
 * Linq To SystemSearch
 * 
 *
 * This is an example of how extend LinQ using IQueruable and IOrderedQuerable interfaces.
 * 
 * User this code as you want,  is free.
 * 
 * Develop by: Mario Rodriguez
 * email: marior666@hotmail.com
 * 
 ********************************************************************************************/


using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace System.Search.Linq
{
    class SystemIndexQueryProvider<T> : IQueryProvider
    {
        SystemIndexContext context;

        public SystemIndexQueryProvider( SystemIndexContext c ) {

            context = c;
        
        }
        #region IQueryProvider Members

        public IQueryable<TElement> CreateQuery<TElement>(System.Linq.Expressions.Expression expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            return new SystemIndexListQuery<TElement>(context,expression);
        }

        public IQueryable CreateQuery(System.Linq.Expressions.Expression expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            return new SystemIndexListQuery<T>(context,expression);
        }

        public TResult Execute<TResult>(System.Linq.Expressions.Expression expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            // Only acepted method calls

            MethodCallExpression mc = expression as MethodCallExpression;
            
            if (mc != null && mc.Method.DeclaringType == typeof(Queryable))
            {
               
                if (mc.Method.Name == "First" || mc.Method.Name == "FirstOrDefault")
                {
                    // Method first and Method First or default is implemented into the query parser too
                    // so, the result will contain only one element.
                    IEnumerator<TResult> enumerator = context.Execute<TResult>(expression);

                    // if has an element then return this element
                    
                    if (enumerator.MoveNext())
                    {
                        return enumerator.Current;
                    }

                    // if method is "First" and has not elements then throw 
                    // an error, Empty Secuence
                    if (mc.Method.Name.Equals("First"))
                    {
                        throw RuntimeErrors.EmptySequence();
                    }
                    // return the default value for "FirstOrDefault"
                    return default(TResult);
                }
                else
                    throw RuntimeErrors.UnsupportedQueryOperator(mc.Method.Name);
            }

            throw RuntimeErrors.FatalError();
        }

        public object Execute(System.Linq.Expressions.Expression expression)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
